﻿/*
 *********************************************************************
 *    Management Extensions for Windows Windows Server AppFabric     *
 *********************************************************************
 *    Author    : Fatih Boy [fatih@enterprisecoding.com]             *
 *    Web site  : http://www.enterprisecoding.com                    *
 *********************************************************************
 *    License   : GNU Library General Public License (LGPL)          * 
 *********************************************************************
 */

using System;
using System.Threading;
using System.Collections.Generic;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;

namespace Com.Enterprisecoding.AppFabric.Extensions.Powershell {
    internal class ExtensionsRunspacePool {
        #region Data Members
        private ExtensionsHost host;
        private InitialSessionState sessionState;
        private object lockObject = new object();
        private List<Runspace> avaliableRunspaces;
        private List<Runspace> busyRunspaces;
        #endregion

        public event EventHandler<EventArgs> RunspaceAvailable;


        public ExtensionsRunspacePool(ExtensionsHost host, InitialSessionState sessionState) {
            this.host = host;
            this.sessionState = sessionState;

            avaliableRunspaces = new List<Runspace>();
            busyRunspaces = new List<Runspace>();
        }

        private Runspace CreateRunspace() {
            var runspace = RunspaceFactory.CreateRunspace(host, sessionState);
            runspace.ThreadOptions = PSThreadOptions.UseNewThread;
            runspace.Open();

            return runspace;
        }

        public Runspace GetRunspace() {
            lock (lockObject) {
                if (avaliableRunspaces.Count!=0) {
                    var runspace = avaliableRunspaces[0];
                    avaliableRunspaces.RemoveAt(0);
                    busyRunspaces.Add(runspace);

                    return runspace;
                }
                else {
                    var runspace = CreateRunspace();
                    busyRunspaces.Add(runspace);

                    return runspace;
                }
            }
        }

        public void ReleaseRunspace(Runspace runspace) {
            lock (lockObject) {
                avaliableRunspaces.Add(runspace);

                FireRunspaceAvaliable();
            }
        }

        public void CreateRunspaceAsync() {
            ThreadPool.QueueUserWorkItem(new WaitCallback(InitializeRunspaceWorker));
        }

        private void InitializeRunspaceWorker(object state) {
            lock (lockObject) {
                var runspace = CreateRunspace();
                avaliableRunspaces.Add(runspace);
            }

            FireRunspaceAvaliable();
        }

        private void FireRunspaceAvaliable() {
            if (RunspaceAvailable != null) {
                RunspaceAvailable(this, new EventArgs());
            }
        }
    }
}